﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Core
{
    public class UICircular<T> : UIWidget, IUICircular
        where T : UIWidget
    {
        private readonly List<T> elements = new();
        private readonly Dictionary<T, int> indexDict = new();
        private ICircularGrid grid;

        private Action<T, int> updateFunc;
        private Action<T, int> selectFunc;
        private Action<string, T, int> eventFunc;

        public void SetUpdateFunc(Action<T, int> func) => updateFunc = func;
        public void SetSelectFunc(Action<T, int> func) => selectFunc = func;
        public void SetEventFunc(Action<string, T, int> func) => eventFunc = func;

        public int Count => elements.Count;

        public override void Awake(GameObject go)
        {
            base.Awake(go);

            grid = go.GetComponent<ICircularGrid>();
            if (grid == null)
            {
                throw new Exception("ERROR! UICircularGrid Need ICircularGrid");
            }

            var cnt = grid.Init();

            grid.SetUpdateFunc(OnGridUpdateHandler);
            grid.SetSelectFunc(OnGridSelectHandler);

            elements.Clear();
            //var tt = typeof(T);
            //var tt1 = typeof(UICircularElement);
            var flag = typeof(UICircularElement).IsAssignableFrom(typeof(T));
            for (int i = 0; i < cnt; i++)
            {
                T t;
                if (flag)
                {
                    t = G.Factory.Create<T, IUICircular, GameObject>(this, transform.GetChild(i).gameObject);
                }
                else
                {
                    t = G.Factory.Create<T, GameObject>(transform.GetChild(i).gameObject);
                }
                t.Init();
                elements.Add(t);
            }
        }

        public override void Dispose()
        {
            if (IsDisposed) return;
            base.Dispose();

            updateFunc = null;
            selectFunc = null;

            for (int i = 0; i < elements.Count; i++)
            {
                elements[i].Dispose();
            }
            elements.Clear();
        }

        public T Find(int index)
        {
            if (index >= 0 && index < elements.Count)
            {
                return elements[index];
            }
            return default;
        }

        public T Find(Predicate<T> func)
        {
            for (int i = 0; i < elements.Count; i++)
            {
                var c = elements[i];
                if (func?.Invoke(c) == true)
                {
                    return c;
                }
            }
            return default;
        }

        //TODO:BUG,elements长度与amount不匹配
        public void SetAmount(int amount)
        {
            grid.SetAmount(amount);

            S.mono.StartCoroutine(DelayFunc());
        }

        IEnumerator DelayFunc()
        {
            yield return 0;

            grid.SetNormalizedPosition(defaultNormalizedPosition);
        }

        private float defaultNormalizedPosition = 0;
        public void SetDefaultNormalizedPosition(float value)
        {
            defaultNormalizedPosition = value;
        }

        public void SetNormalizedPosition(float value)
        {
            grid.SetNormalizedPosition(value);
        }

        public void Refresh()
        {
            foreach (var element in elements)
            {
                if (indexDict.ContainsKey(element) == false) continue;
                var index = indexDict[element];
                updateFunc?.Invoke(element, index);
            }
        }

        public void Scroll2Element(int index)
        {

        }

        public void Scroll2NormalizedPosition(float value)
        {

        }

        public override void SetActive(bool active)
        {
            base.SetActive(active);

            foreach (var element in elements)
            {
                element.SetActive(active);
            }
        }

        private void OnGridUpdateHandler(int index)
        {
            var element = elements[index % Count];

            indexDict[element] = index;

            if (element is ICircularElementUpdate obj)
            {
                obj.Refresh(index);
            }
            updateFunc?.Invoke(element, index);
        }

        private ICircularElementSelect currT;
        private int currT_Index;

        private void OnGridSelectHandler(int index)
        {
            var element = elements[index % Count];

            if (currT != null)
            {
                currT.Select(currT_Index, false);
            }

            if (element is ICircularElementSelect obj)
            {
                currT = obj;
                currT_Index = index;
            }

            if (currT != null)
            {
                currT.Select(currT_Index, true);
            }

            selectFunc?.Invoke(element, index);
        }

        public void Dispatch(string key, UICircularElement element)
        {
            if (element is not T t)
            {
                return;
            }
            //var index = elements.IndexOf(t);
            var index = indexDict[t];
            eventFunc?.Invoke(key, t, index);
        }
    }
}
